#include "typedef.h"
#include "queueapi.h"
#include "mapapi.h"

static unsigned hashing(word object)
{
    unsigned key = object & 0xff;
    key ^= (object >> 8) & 0xff;
    key ^= (object >> 16) & 0xff;
    return key & 0b1111;
}

static unsigned hashing_str(const char *name)
{
    unsigned key = 0;
    while (*name)
    {
        key ^= *name;
        name++;
    }
    return key &0b1111;
    
}

void init_hashmap(HashMap m)
{
    for(int i=0; i<16; i++)
    {
        queue_init(&m->slots[i]);
    }
}

boolean insert_object(HashMap m, HashNode n, object key, object value)
{
    unsigned _key = hashing(CAST_AS(word, key));
    Queue slotq = &m->slots[_key];
    queue_push(slotq, &n->qn);
    n->value = value;
    n->key = key;
    return True;
}

HashNode find_object(HashMap m, object key)
{
    HashNode node = CAST_AS(HashNode, NULL);
    unsigned _key = hashing(CAST_AS(word, key));
    Queue slotq = &m->slots[_key];
    QueueNode n = slotq->first;
    for (; n; n = n->next)
    {
        HashNode hn = CONTAINER_OF(HashNode, qn, n);
        if (hn->key == key)
        {
            node = hn;
            break;
        }
    }
    return node;
}

boolean delete_object(HashMap m, object key)
{
    HashNode node = CAST_AS(HashNode, NULL);
    unsigned _key = hashing(CAST_AS(word, key));
    Queue slotq = &m->slots[_key];
    QueueNode n = slotq->first;
    for (; n; n = n->next)
    {
        HashNode hn = CONTAINER_OF(HashNode, qn, n);
        if (hn->key == key)
        {
            node = hn;
            break;
        }
    }
    if (!node)
    {
        return False;
    }
    queue_remove(slotq, &node->qn);
    return True;
}

#define MAX_STR (10)

boolean insert_object_str(HashMap m, HashNode n, const char *key, object value)
{
    unsigned _key = hashing_str(key);
    Queue slotq = &m->slots[_key];
    queue_push(slotq, &n->qn);
    n->value = value;
    n->key = CAST_AS(object, key);
    return True;
}

#include "strapi.h"
HashNode find_object_str(HashMap m, const char *key)
{
    HashNode node = CAST_AS(HashNode, NULL);
    unsigned _key = hashing_str(key);
    Queue slotq = &m->slots[_key];
    QueueNode n = slotq->first;
    for (; n; n = n->next)
    {
        HashNode hn = CONTAINER_OF(HashNode, qn, n);
        if (strncmp(key, CAST_AS(const char*, hn->key), MAX_STR) == 0)
        {
            node = hn;
            break;
        }
    }
    return node;
}

boolean delete_object_str(HashMap m, const char *key)
{
    HashNode node = CAST_AS(HashNode, NULL);
    unsigned _key = hashing_str(key);
    Queue slotq = &m->slots[_key];
    QueueNode n = slotq->first;
    for (; n; n = n->next)
    {
        HashNode hn = CONTAINER_OF(HashNode, qn, n);
        if (hn->key == key)
        {
            node = hn;
            break;
        }
    }
    if (!node)
    {
        return False;
    }
    queue_remove(slotq, &node->qn);
    return True;
}